package com.firebird.app.kotlin.stock.trend.net

import android.os.Bundle
import android.os.Handler
import android.os.Message
import com.firebird.app.kotlin.stock.trend.bean.Stock
import com.firebird.app.kotlin.stock.trend.utils.Constant
import com.firebird.app.kotlin.stock.trend.utils.Log
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.ObjectInputStream
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.ClosedChannelException
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.nio.channels.SocketChannel


/**
 * 进行Socket通信的客户端连接类
 * 只进行原始数据的发送与接收操作
 * @author ljk
 * @date   2019年12月24日
 */
class StockDataSource(ip: String, port: Int) : Thread() {
    private var selector: Selector? = null
    private var channel: SocketChannel? = null
    private var readBuffer: ByteBuffer?=null
    private var serviceHandler //UI线程中的handler
            : Handler? = null
    private var isRunning = true
    private val ip: String
    private val port: Int
    /**
     * 传入UI线程中的handler，请求处理完成后通知UI线程更新数据
     * @param serviceHandler
     */
    fun setServiceHandler(serviceHandler: Handler?) {
        this.serviceHandler = serviceHandler
    }

    /**
     * 获取股票排行数据
     * @param recordNum
     */
    fun getStockRank(bundle: Bundle) {
        val buffer = ByteBuffer.allocate(48)
        buffer.putInt(Constant.SERVICE_QUOTATION_RANK_REQUEST)
        buffer.putInt(bundle.getInt("flag"))
        buffer.putInt(bundle.getInt("start"))
        buffer.putInt(bundle.getInt("wantnum"))
        buffer.putInt(bundle.getInt("colunm"))
        buffer.putInt(bundle.getInt("desc"))
        buffer.flip()
        try {
            channel!!.write(buffer)
            Log.d(tag, "NIO --> 向服务器发出写操作！")
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /**
     * 关闭与服务器的连接
     */
    fun close() {
        isRunning = false
    }

    override fun run() {
        initClient()
        startClient() //该方法会在内部循环监听
        Log.d(tag, "通信线程启动成功！")
    }

    /**
     * 初始化与服务器的连接通道
     * @throws IOException
     */
    private fun initClient() {
        try { // 获得一个Socket通道
            channel = SocketChannel.open()
            // 设置通道为非阻塞
            channel?.configureBlocking(false)
            // 获得一个通道管理器
            selector = Selector.open()
            // 客户端连接服务器,其实方法执行并没有实现连接，需要在listen（）方法中调
//用channel.finishConnect();才能完成连接
            channel?.connect(InetSocketAddress(ip, port))
            channel?.register(selector, SelectionKey.OP_CONNECT)
        } catch (e: ClosedChannelException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /**
     * 启动监听操作
     */
    private fun startClient() {
        try {
            while (isRunning) {
                selector!!.select()
                val iterator = selector!!.selectedKeys().iterator()
                while (iterator.hasNext()) {
                    val selectionKey = iterator.next()
                    iterator.remove() // 删除已选的key,以防重复处理
                    if (selectionKey.isConnectable) { // 连接事件发生
                        channel = selectionKey.channel() as SocketChannel
                        // 如果正在连接，则完成连接
                        if (channel!!.isConnectionPending) {
                            channel!!.finishConnect()
                        }
                        channel!!.configureBlocking(false)
                        channel!!.register(selector, SelectionKey.OP_READ)
                    } else if (selectionKey.isReadable) {
                        read(selectionKey)
                    }
                }
            }
            channel!!.close() //关闭通道
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    @Throws(IOException::class)
    private fun read(key: SelectionKey) { // 服务器可读取消息:得到事件发生的Socket通道
        val channel = key.channel() as SocketChannel
        readBuffer!!.clear()
        channel.read(readBuffer)
        val position = readBuffer!!.position()
        println(position)
        readBuffer!!.flip()
        val flag = readBuffer!!.getInt(0)
        val bios = ByteArrayInputStream(readBuffer!!.array(), 4, position) //一个int值在readBuffer占4个byte
        val ois = ObjectInputStream(bios)
        try {
            val stocks = ois.readObject() as List<Stock>
            /*if(stocks != null){
				for(Stock s : stocks){
					System.out.println("=========>>股票名称："+s.getName()+" 股票代码："+s.getCode()+ " 现价："+s.getNowPrice());
				}
			}*/Log.d(tag, "NIO --> 成功读取服务器传回的数据！")
            val msg = Message()
            msg.what = Constant.SERVICE_QUOTATION_RANK_REQUEST
            msg.arg1 = flag //原样返回的标识位
            msg.obj = stocks
            serviceHandler!!.sendMessage(msg)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
    }

    companion object {
        private const val tag = "StockDataSource"
    }

    init {
        readBuffer = ByteBuffer.allocate(8056)
        this.ip = ip
        this.port = port
    }
}
